/* $Id: TournamentLoader.java 110M 2009-06-07 21:11:45Z (local) $ */
package org.jugger.tournament.model.loader;

import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.Vector;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.jugger.tournament.model.MatchTemplate;
import org.jugger.tournament.model.MatchTemplates;
import org.jugger.tournament.model.Team;
import org.jugger.tournament.model.Tournament;
import org.jugger.tournament.model.ranking.RankingComparator;
import org.jugger.tournament.model.score.ScoreCalculator;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class TournamentLoader {

	public static Tournament loadFromXML(URL url) {
		TournamentXMLHandler handler = new TournamentXMLHandler();

		// // build an XSD-aware SchemaFactory
		// SchemaFactory schemaFactory = SchemaFactory.newInstance(
		// XMLConstants.W3C_XML_SCHEMA_NS_URI );
		// // hook up org.xml.sax.ErrorHandler implementation.
		// schemaFactory.setErrorHandler( handler );
		// // get the custom xsd schema describing the required format for my
		// XML files.
		// Schema schemaXSD = schemaFactory.newSchema( null ); //new File (
		// "myschema.xsd" ) );
		// // Create a Validator capable of validating XML files according to my
		// custom schema.
		// Validator validator = schemaXSD.newValidator();
		//
		// // Get a parser capable of parsing vanilla XML into a DOM tree
		// DocumentBuilder parser =
		// DocumentBuilderFactory.newInstance().newDocumentBuilder();
		// // parse the XML purely as XML and get a DOM tree represenation.
		// Document document = parser.parse( input );
		// // parse the XML DOM tree againts the stricter XSD schema
		// validator.validate( new DOMSource( document ) );

		InputSource input = new InputSource(url.toString());
		SAXParserFactory parserFactory = SAXParserFactory.newInstance();
		parserFactory.setValidating(true);
		parserFactory.setNamespaceAware(true);

		try {
			SAXParser parser = parserFactory.newSAXParser();
			parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
					"http://www.w3.org/2001/XMLSchema");
			parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", ClassLoader
					.getSystemResource("tournament_v1.xsd").getContent());

			XMLReader reader = parser.getXMLReader();
			reader.setContentHandler(handler);
			reader.setErrorHandler(handler);
			// reader.setEntityResolver(resolver)

			try {
				reader.parse(input);
				return handler.createTournament();
			} catch (IOException e) {
				// e.printStackTrace();
			}
		} catch (ParserConfigurationException e) {
			// e.printStackTrace();
		} catch (SAXException e) {
			// e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private static class TournamentXMLHandler extends DefaultHandler {

		enum ElementTag {
			scoreCalculator, rankingComparator, team, round, match
		}

		@Override
		public void warning(SAXParseException e) throws SAXException {
			System.out.println("WARNING: " + e);
			throw e;
		}

		@Override
		public void error(SAXParseException e) throws SAXException {
			System.out.println("ERROR: " + e);
			throw e;
		}

		@Override
		public void fatalError(SAXParseException e) throws SAXException {
			System.out.println("FATAL ERROR: " + e);
			throw e;
		}

		private Vector<Team> teams = new Vector<Team>();
		private Vector<MatchTemplates> rounds = new Vector<MatchTemplates>();
		private RankingComparator rankingComparator = null;
		private ScoreCalculator scoreCalculator = null;

		public Tournament createTournament() {
			HashSet<Team> teamsSet = new HashSet<Team>(teams);
			if (teams.size() != teamsSet.size())
				throw new RuntimeException("Invalid team quantity.");
			return new Tournament(rankingComparator, scoreCalculator, teamsSet, rounds);
		}

		@Override
		public void startElement(String uri, String localName, String name, Attributes attributes)
				throws SAXException {
			try {
				switch (ElementTag.valueOf(name)) {
				case scoreCalculator:
					scoreCalculator = ScoreCalculator.getFromPrefix(attributes.getValue("type"));
					break;
				case rankingComparator:
					rankingComparator = RankingComparator
							.getFromPrefix(attributes.getValue("type"));
					break;
				case team:
					boolean isAdditionalTeam = attributes.getValue("isAdditionalTeam") == null ? false
							: Boolean.parseBoolean(attributes.getValue("isAdditionalTeam"));
					teams.add(new Team(attributes.getValue("name"), attributes.getValue("city"),
							isAdditionalTeam));
					break;
				case round:
					rounds.add(new MatchTemplates());
					break;
				case match:
					Team teamA = teams.get(Integer.parseInt(attributes.getValue("teamA")));
					Team teamB = teams.get(Integer.parseInt(attributes.getValue("teamB")));
					int pointsA = Integer.parseInt(attributes.getValue("pointsA"));
					int pointsB = Integer.parseInt(attributes.getValue("pointsB"));
					boolean isFinished = attributes.getValue("finished") == null ? false : Boolean
							.parseBoolean(attributes.getValue("finished"));
					boolean extraTime = attributes.getValue("extraTime") == null ? false : Boolean
							.parseBoolean(attributes.getValue("extraTime"));
					rounds.lastElement()
							.add(
									new MatchTemplate(teamA, teamB, pointsA, pointsB, extraTime,
											isFinished));
				}
			} catch (IllegalArgumentException iae) {
			}
		}

	}

}
